package com.ts.api.module.api.service.impl;

import com.gitee.apanlh.util.base.BigDecimalUtils;
import com.gitee.apanlh.util.base.CollUtils;
import com.gitee.apanlh.util.base.Empty;
import com.gitee.apanlh.util.base.Eq;
import com.gitee.apanlh.util.base.IteratorUtils;
import com.gitee.apanlh.util.base.StringUtils;
import com.gitee.apanlh.util.dataformat.JsonUtils;
import com.gitee.apanlh.util.date.DateUtils;
import com.gitee.apanlh.util.log.Log;
import com.gitee.apanlh.util.reflection.CopyUtils;
import com.gitee.apanlh.util.valid.Assert;
import com.gitee.apanlh.util.valid.RegexUtils;
import com.gitee.apanlh.util.valid.ValidParam;
import com.ts.api.common.constant.api.ApiBizTypeEnum;
import com.ts.api.common.constant.api.ApiEnum;
import com.ts.api.common.constant.api.ApiVersionEnum;
import com.ts.api.common.constant.api.ApiVersionModeEnum;
import com.ts.api.common.constant.channel.ChannelIsRegisterEnum;
import com.ts.api.common.constant.common.SwitchEnum;
import com.ts.api.common.constant.product.ProductPlanVersionEnum;
import com.ts.api.common.constant.product.ProductPlanVersionMode;
import com.ts.api.common.constant.productflow.ProductApplyFlowStatusEnum;
import com.ts.api.common.localcache.DistrictCache;
import com.ts.api.common.redis.Md5DataFilterRedisKey;
import com.ts.api.common.util.OpenTimeUtils;
import com.ts.api.exp.ApiMsgException;
import com.ts.api.module.api.convert.core.http.client.ApiHttpMessage;
import com.ts.api.module.api.convert.org.model.RespOrgPhoneMaskDataExchange;
import com.ts.api.module.api.convert.platform.entity.RespPlatformFederateForm;
import com.ts.api.module.api.convert.platform.entity.RespPlatformMultiPhoneMaskDataExchange;
import com.ts.api.module.api.convert.platform.entity.RespPlatformPhoneMaskDataExchange;
import com.ts.api.module.api.convert.platform.entity.RespPlatformPhoneMd5DataExchange;
import com.ts.api.module.api.entity.ApiUserRequest;
import com.ts.api.module.api.entity.bo.ApiBizMatchBO;
import com.ts.api.module.api.entity.bo.ApiCheckHistoryUserBO;
import com.ts.api.module.api.entity.bo.ApiFilterParamBO;
import com.ts.api.module.api.entity.bo.ApiParameterBO;
import com.ts.api.module.api.entity.bo.ApiPreRequiredBO;
import com.ts.api.module.api.entity.bo.ApiRequiredFlowBO;
import com.ts.api.module.api.entity.po.ApiKeyPO;
import com.ts.api.module.api.entity.vo.ReqApiParameterVO;
import com.ts.api.module.api.service.ApiBizRequiredService;
import com.ts.api.module.channel.entity.bo.SelectedUserFormBO;
import com.ts.api.module.channel.entity.bo.UserMappingRegisterBO;
import com.ts.api.module.channel.entity.po.ChannelPO;
import com.ts.api.module.channel.entity.po.ChannelUserFormPO;
import com.ts.api.module.channel.entity.po.ChannelUserRegisterPO;
import com.ts.api.module.channel.entity.qo.ChannelUserQO;
import com.ts.api.module.channel.service.ChannelHistoryUserService;
import com.ts.api.module.channel.service.ChannelUserService;
import com.ts.api.module.channel.service.DoubleWriteUserService;
import com.ts.api.module.common.entity.DistrictPO;
import com.ts.api.module.common.entity.bo.CheckPhoneStatusBO;
import com.ts.api.module.common.service.UserPhoneAuthService;
import com.ts.api.module.filter.service.DataFilterService;
import com.ts.api.module.product.entity.po.ProductApplyFlowPO;
import com.ts.api.module.product.entity.po.ProductPlanFieldPO;
import com.ts.api.module.product.entity.po.ProductPlanFilterChannelPO;
import com.ts.api.module.product.entity.po.ProductPlanPO;
import com.ts.api.module.product.entity.qo.ProductApplyFlowQO;
import com.ts.api.module.product.entity.qo.ProductPlanFieldQO;
import com.ts.api.module.product.service.ProductAmountService;
import com.ts.api.module.product.service.ProductApplyFlowService;
import com.ts.api.module.product.service.ProductPlanFieldService;
import com.ts.api.module.product.service.ProductPlanFilterChannelService;
import com.ts.api.module.product.service.ProductPlanLimitService;
import com.ts.api.module.product.service.ProductPlanTypeService;
import com.ts.cache.apikey.ApiKeyCacheService;
import com.ts.cache.apikey.ApiKeyRuleCacheService;
import com.ts.cache.apikey.entity.ApiKeyCache;
import com.ts.cache.apikey.entity.ApiKeyListRuleCache;
import com.ts.cache.apikey.entity.ApiKeyRuleCache;
import com.ts.cache.form.FormCacheService;
import com.ts.cache.form.entity.FormCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 *  API业务验证方法
 *
 *  @author Pan
 */
@Service
public class ApiBizRequiredServiceImpl implements ApiBizRequiredService {

    /**  时间比较器 */
    private static final Comparator<String> DATE_TIME_COMPARATOR = DateUtils::dateTimeCompareTo;

    @Autowired
    private ProductApplyFlowService productApplyFlowService;
    @Autowired
    private ProductPlanLimitService productPlanLimitService;
    @Autowired
    private ProductPlanFieldService productPlanFieldService;
    @Autowired
    private ProductAmountService productAmountService;
    @Autowired
    private ProductPlanFilterChannelService productPlanFilterChannelService;
    @Autowired
    private ProductPlanTypeService productPlanTypeService;
    @Autowired
    private DataFilterService apiDataFilterService;
    @Autowired
    private ChannelUserService channelUserService;
    @Autowired
    private DataFilterService dataFilterService;
    @Autowired
    private ApiKeyRuleCacheService apiKeyRuleCacheService;
    @Autowired
    private FormCacheService formCacheService;
    @Autowired
    private UserPhoneAuthService userPhoneAuthService;
    @Autowired
    private ApiKeyCacheService apiKeyCacheService;
    @Autowired
    private ChannelHistoryUserService channelHistoryUserService;
    @Autowired
    private DoubleWriteUserService doubleWriteUserService;

    @Override
    public List<ProductApplyFlowPO> existFailFlow(String apiClient, String phoneMd5) {
        //  关联流程状态集合
        List<Integer> statusList = CollUtils.newArrayList(newList -> {
            newList.add(ProductApplyFlowStatusEnum.DATA_EXCHANGE_FAIL.getType());
            newList.add(ProductApplyFlowStatusEnum.APPLY_ERROR.getType());
            newList.add(ProductApplyFlowStatusEnum.CHANNEL_DATA_EXCHANGE.getType());
            newList.add(ProductApplyFlowStatusEnum.USER_ACCEPT.getType());
            newList.add(ProductApplyFlowStatusEnum.DATA_EXCHANGE_SUC.getType());
        });

        //  查询归属状态
        ProductApplyFlowQO productApplyFlowQO = new ProductApplyFlowQO();
        productApplyFlowQO.setPhoneMd5(phoneMd5);
        productApplyFlowQO.setApiClientId(apiClient);
        productApplyFlowQO.setStatusList(statusList);
        List<ProductApplyFlowPO> listFlow = productApplyFlowService.listForDataExchange(productApplyFlowQO);
        //  如果未查询到归属状态直接返回
        if (ValidParam.isEmpty(listFlow)) {
            return listFlow;
        }

        //  分组转换流程状态
        Map<Integer, List<ProductApplyFlowPO>> flowMap = CollUtils.groupBy(listFlow, t -> t.getStatus());

        //  检测是否有成功的条目-如果不存在成功条目直接返回
        List<ProductApplyFlowPO> dataChangeSuc = flowMap.get(ProductApplyFlowStatusEnum.DATA_EXCHANGE_SUC.getType());
        if (ValidParam.isNotEmpty(dataChangeSuc)) {
            return listFlow;
        }

        //  存在撞库失败
        List<ProductApplyFlowPO> dataChangeFail = flowMap.get(ProductApplyFlowStatusEnum.DATA_EXCHANGE_FAIL.getType());
        Assert.isEmptyThrows(dataChangeFail, new ApiMsgException(ApiEnum.API_BIZ_FLOW_DATA_CHANGE_FAIL));

        //  存在进件失败
        List<ProductApplyFlowPO> applyError = flowMap.get(ProductApplyFlowStatusEnum.APPLY_ERROR.getType());
        Assert.isEmptyThrows(applyError, new ApiMsgException(ApiEnum.API_BIZ_FLOW_APPLY_FAIL));

        //  如存在撞库成功流程
        List<ProductApplyFlowPO> listDataExchange = flowMap.get(ProductApplyFlowStatusEnum.CHANNEL_DATA_EXCHANGE.getType());
        //  是否存在撞库成功流程
        if (ValidParam.isNotEmpty(listDataExchange)) {
            //  是否存在授权节点
            List<ProductApplyFlowPO> listAccept = flowMap.get(ProductApplyFlowStatusEnum.USER_ACCEPT.getType());
            Assert.isEmptyThrows(listAccept, new ApiMsgException(ApiEnum.API_BIZ_FLOW_EXIST));
        }
        return listFlow;
    }

    @Override
    public ApiParameterBO preRequiredParam(ApiPreRequiredBO apiPreRequiredBO) {
        ReqApiParameterVO reqApiParameterVO = apiPreRequiredBO.getReqApiParameterVO();

        ApiKeyPO apiKeyPO = reqApiParameterVO.getApiKeyPO();
        String apiClientId = apiKeyPO.getApiClientId();
        Long loanChannelId = apiKeyPO.getLoanChannelId();

        ApiFilterParamBO apiFilterParamBO = apiPreRequiredBO.getApiFilterParamBO();
        ApiBizTypeEnum apiBizTypeEnum = apiPreRequiredBO.getApiBizTypeEnum();
        ApiBizMatchBO apiBizMatchBO = apiPreRequiredBO.getApiBizMatchBO();

        //  是否过滤参数
        Map<String, String> mapReqForm;
        if (ValidParam.isNotNull(apiFilterParamBO)) {
            mapReqForm = apiFilterParamBO.filterMap(reqApiParameterVO);
        } else {
            mapReqForm = reqApiParameterVO.getFormMap();
        }

        //  获取前置业务参数条件验证
        ApiKeyListRuleCache apiKeyListRuleCache = apiKeyRuleCacheService.get(apiClientId);
        Assert.isNotNullThrows(apiKeyListRuleCache, new ApiMsgException(ApiEnum.API_REQUIRED_CONFIG));
        List<ApiKeyRuleCache> listApiRequiredRule = apiBizTypeEnum.hasEnum(ApiBizTypeEnum.DATA_EXCHANGE) ? apiKeyListRuleCache.getListDataExchangeRule() : apiKeyListRuleCache.getListApplyRule();

        // 验证是否存在必填包含参数
        IteratorUtils.array(listApiRequiredRule, t ->
            Assert.isTrue(mapReqForm.containsKey(t.getMappingName()), () -> {throw new ApiMsgException(ApiEnum.API_REQUIRED_PARAM_NULL.format(t.getMappingName()));})
        );

        //  注册映射
        UserMappingRegisterBO mappingRegisterBO = UserMappingRegisterBO.convertBO(mapReqForm);
        //  表单映射
        List<SelectedUserFormBO> listMappingFormBO = CollUtils.newArrayList();

        //  获取表单及表单值缓存对象-并校验参数是否为合法值
        List<FormCache> listForm = formCacheService.get();
        Map<String, List<FormCache>> formMap = CollUtils.groupByToLinked(listForm, FormCache::getMappingName);
        //  获取用户注册信息字段
        List<String> listRegisterName = mappingRegisterBO.getRegisterFieldNames();

        //  校验传递参数
        IteratorUtils.entrySet(mapReqForm, (k, v) -> {
            //  根据映射名称找表单集合
            List<FormCache> listFormByMappingName = formMap.get(k);
            //  空参数跳过或找不到参数则跳过
            if (ValidParam.isEmpty(v) || ValidParam.isEmpty(listFormByMappingName)) {
                return ;
            }

            //  检测不包含用户信息项的值,只验证表单资质项
            if (!listRegisterName.contains(k)) {
                Assert.isTrue(ValidParam.isNumber(v), () -> {throw new ApiMsgException(ApiEnum.API_REQUIRED_PARAM_ERROR.format(k));});

                //  校验传递参数值是否存在表单字典中
                for (int i = 0, len = listFormByMappingName.size(); i < len; i++) {
                    FormCache formCache = listFormByMappingName.get(i);
                    //  如果存在则添加最终表单值
                    if (Eq.str(formCache.getMappingValue(), v)) {
                        SelectedUserFormBO selectedUserFormBO = SelectedUserFormBO.convertBO(
                            formCache.getFormFieldId(),
                            formCache.getFormFieldValueId(),
                            formCache.getMappingName(),
                            formCache.getMappingValue(),
                            formCache.getFieldName(),
                            formCache.getFieldValue()
                        );
                        listMappingFormBO.add(selectedUserFormBO);
                        break;
                    }
                    //  如果此值未出现在字典值中，则抛出异常
                    if (CollUtils.isLastIndex(listFormByMappingName, i)) {
                        throw new ApiMsgException(ApiEnum.API_REQUIRED_PARAM_VALUE_RANGE_ERROR.format(k));
                    }
                }
            }
        });

        String phoneMd5 = mappingRegisterBO.getPhoneMd5();
        //  增加md5库及添加md5过滤筛选库存在标识
        if (ValidParam.isNull(Md5DataFilterRedisKey.MD5_EXIST_FILTER.get(phoneMd5))) {
            int md5Row = dataFilterService.insert(phoneMd5);
            //  如果首次标识将计1个小时, 否则如果已存在md5标识将只存在10秒钟
            if (md5Row > 0) {
                Md5DataFilterRedisKey.MD5_EXIST_FILTER.setIfAbsent(phoneMd5, true, 1L, TimeUnit.HOURS);
            } else {
                Md5DataFilterRedisKey.MD5_EXIST_FILTER.setIfAbsent(phoneMd5, false, 10L, TimeUnit.SECONDS);
            }
        }

        //  是否存在phoneMd5手机号
        int phoneMd5Row = channelUserService.countByPhoneMd5(phoneMd5);
        boolean hasLocalExist = phoneMd5Row > 0;

        //  返回API业务参数实体
        ApiParameterBO apiPreRequiredParamBO = new ApiParameterBO();
        apiPreRequiredParamBO.setApiKeyPO(apiKeyPO);
        apiPreRequiredParamBO.setApiBizMatchBO(apiBizMatchBO);
        apiPreRequiredParamBO.setReqApiParameterVO(reqApiParameterVO);
        apiPreRequiredParamBO.setUserRegisterBO(mappingRegisterBO);
        apiPreRequiredParamBO.setListUserFormBO(listMappingFormBO);
        apiPreRequiredParamBO.setHasLocalExist(hasLocalExist);

        //  撞库校验业务
        if (ApiBizTypeEnum.DATA_EXCHANGE.hasEnum(apiBizTypeEnum)) {
            //  验证关键参数
            Assert.isNotEmptyThrows(phoneMd5, new ApiMsgException(ApiEnum.API_REQUIRED_BASE_PARAM_NULL.format("phoneMd5")));
            Assert.isTrueThrows(phoneMd5.length() == 32, new ApiMsgException(ApiEnum.API_PARAM_ERROR));
            Assert.isTrueThrows(RegexUtils.isNumEnglish(phoneMd5), new ApiMsgException(ApiEnum.API_PARAM_ERROR));

            String city = mappingRegisterBO.getCity();
            Assert.isNotEmptyThrows(city, new ApiMsgException(ApiEnum.API_REQUIRED_BASE_PARAM_NULL.format("city")));
            Assert.isTrueThrows(city.length() >= 2, new ApiMsgException(ApiEnum.API_PARAM_ERROR));
            Assert.isTrueThrows(RegexUtils.isChinese(city), new ApiMsgException(ApiEnum.API_PARAM_ERROR));

            //  异步处理:如果API传递的带名字-更新历史库姓名
            if (ValidParam.isEmpty(mappingRegisterBO.getUserName())) {
                Thread.startVirtualThread(() -> {
                    ChannelUserRegisterPO historyUser = channelHistoryUserService.get(ChannelUserQO.createPhoneMd5(phoneMd5));
                    //  如果存在历史库中-更新姓名，性别，城市
                    if (ValidParam.isNotNull(historyUser)) {
                        ChannelUserRegisterPO updateUserPO = new ChannelUserRegisterPO();
                        updateUserPO.setId(historyUser.getId());
                        updateUserPO.setUserName(mappingRegisterBO.getUserName());

                        if (ValidParam.isNotEmpty(mappingRegisterBO.getSex())) {
                            updateUserPO.setSex(mappingRegisterBO.getSex());
                        }

                        DistrictPO districtPO = DistrictCache.getByName(mappingRegisterBO.getCity());
                        if (ValidParam.isNotNull(districtPO)) {
                            updateUserPO.setAreaCode(districtPO.getCode());
                            updateUserPO.setAreaName(districtPO.getName());
                        }
                        updateUserPO.setIsChannelRegister(ChannelIsRegisterEnum.OLD.getType());
                        channelHistoryUserService.update(updateUserPO);
                    }
                });
            }
        }

        //  进件业务时则验证-手机号是否已注册
        if (ApiBizTypeEnum.APPLY.hasEnum(apiBizTypeEnum)) {
            //  如果进件注册过将姓名更改
            if (hasLocalExist) {
                //  获取当前用户信息
                ChannelUserQO channelUserQO = ChannelUserQO.createPhone(mappingRegisterBO.getPhone());
                ChannelUserRegisterPO channelUserRegisterPO = channelUserService.get(channelUserQO);
                Long userId = channelUserRegisterPO.getId();

                //  如果是联登进来并且用户不填写表单，无姓名问题
                boolean hasFederateNotUserName = ValidParam.isEmpty(channelUserRegisterPO.getUserName());

                //  修改姓名，城市，性别，城市
                ChannelUserRegisterPO updateUser = new ChannelUserRegisterPO();
                updateUser.setId(userId);

                updateUser.setUserName(mappingRegisterBO.getUserName());
                if (ValidParam.isNotEmpty(mappingRegisterBO.getSex())) {
                    updateUser.setSex(mappingRegisterBO.getSex());
                }

                DistrictPO districtPO = DistrictCache.getByName(mapReqForm.get("city"));
                updateUser.setAreaName(districtPO.getName());
                updateUser.setAreaCode(districtPO.getCode());
                updateUser.setIsChannelRegister(ChannelIsRegisterEnum.OLD.getType());
                doubleWriteUserService.updateUser(updateUser);

                //  修改原有表单
                List<ChannelUserFormPO> listChannelUserFormPO = CopyUtils.copyList(listMappingFormBO, ChannelUserFormPO.class);
                IteratorUtils.array(listChannelUserFormPO, t -> {
                    t.setChannelId(loanChannelId);
                    t.setUserId(userId);
                });
                doubleWriteUserService.batchInsertUserForm(listChannelUserFormPO);

                //  如果是联登进来用户注册，无填写表单，并且后续API渠道触发改用户时则不判定用户已存在，将用户信息修改继续API渠道分发
                if (hasFederateNotUserName) {
                    apiPreRequiredParamBO.setHasFederateUser(true);
                    return apiPreRequiredParamBO;
                }

                //  特殊计划将直接返回
                boolean hasOnlySpecialPlan = apiBizMatchBO.hasOnlySpecialPlan();
                if (hasOnlySpecialPlan) {
                    //  判断是否能够正常分发crm
                    return apiPreRequiredParamBO;
                }
            }
            Assert.isFalseThrows(hasLocalExist, new ApiMsgException(ApiEnum.API_USER_INFO_EXIST.format(apiBizTypeEnum.getName())));
        }
        return apiPreRequiredParamBO;
    }

    @Override
    public ApiParameterBO preRequiredParamPhoneMask(ApiPreRequiredBO apiPreRequiredBO) {
        ReqApiParameterVO reqApiParameterVO = apiPreRequiredBO.getReqApiParameterVO();
        ApiKeyPO apiKeyPO = reqApiParameterVO.getApiKeyPO();
        String apiClientId = apiKeyPO.getApiClientId();
        Long loanChannelId = apiKeyPO.getLoanChannelId();

        ApiFilterParamBO apiFilterParamBO = apiPreRequiredBO.getApiFilterParamBO();
        ApiBizTypeEnum apiBizTypeEnum = apiPreRequiredBO.getApiBizTypeEnum();
        ApiBizMatchBO apiBizMatchBO = apiPreRequiredBO.getApiBizMatchBO();

        //  是否过滤参数
        Map<String, String> mapReqForm;
        if (ValidParam.isNotNull(apiFilterParamBO)) {
            mapReqForm = apiFilterParamBO.filterMap(reqApiParameterVO);
        } else {
            mapReqForm = reqApiParameterVO.getFormMap();
        }

        //  获取前置业务参数条件验证
        ApiKeyListRuleCache apiKeyListRuleCache = apiKeyRuleCacheService.get(apiClientId);
        Assert.isNotNullThrows(apiKeyListRuleCache, new ApiMsgException(ApiEnum.API_REQUIRED_CONFIG));
        List<ApiKeyRuleCache> listApiRequiredRule = apiBizTypeEnum.hasEnum(ApiBizTypeEnum.DATA_EXCHANGE) ? apiKeyListRuleCache.getListDataExchangeRule() : apiKeyListRuleCache.getListApplyRule();

        // 验证是否存在必填包含参数
        IteratorUtils.array(listApiRequiredRule, t ->
            Assert.isTrue(mapReqForm.containsKey(t.getMappingName()), () -> {throw new ApiMsgException(ApiEnum.API_REQUIRED_PARAM_NULL.format(t.getMappingName()));})
        );

        //  注册映射
        UserMappingRegisterBO mappingRegisterBO = UserMappingRegisterBO.convertBOByPhoneMask(mapReqForm);
        //  表单映射
        List<SelectedUserFormBO> listMappingFormBO = CollUtils.newArrayList();

        //  获取表单及表单值缓存对象-并校验参数是否为合法值
        List<FormCache> listForm = formCacheService.get();
        Map<String, List<FormCache>> formMap = CollUtils.groupByToLinked(listForm, FormCache::getMappingName);
        //  获取用户注册信息字段
        List<String> listRegisterName = mappingRegisterBO.getRegisterFieldNames();

        //  校验传递参数
        IteratorUtils.entrySet(mapReqForm, (k, v) -> {
            //  根据映射名称找表单集合
            List<FormCache> listFormByMappingName = formMap.get(k);
            //  空参数跳过或找不到参数则跳过
            if (ValidParam.isEmpty(v) || ValidParam.isEmpty(listFormByMappingName)) {
                return ;
            }

            //  检测不包含用户信息项的值,只验证表单资质项
            if (!listRegisterName.contains(k)) {
                Assert.isTrue(ValidParam.isNumber(v), () -> {throw new ApiMsgException(ApiEnum.API_REQUIRED_PARAM_ERROR.format(k));});

                //  校验传递参数值是否存在表单字典中
                for (int i = 0, len = listFormByMappingName.size(); i < len; i++) {
                    FormCache formCache = listFormByMappingName.get(i);
                    //  如果存在则添加最终表单值
                    if (Eq.str(formCache.getMappingValue(), v)) {
                        SelectedUserFormBO selectedUserFormBO = SelectedUserFormBO.convertBO(
                            formCache.getFormFieldId(),
                            formCache.getFormFieldValueId(),
                            formCache.getMappingName(),
                            formCache.getMappingValue(),
                            formCache.getFieldName(),
                            formCache.getFieldValue()
                        );
                        listMappingFormBO.add(selectedUserFormBO);
                        break;
                    }
                    //  如果此值未出现在字典值中，则抛出异常
                    if (CollUtils.isLastIndex(listFormByMappingName, i)) {
                        throw new ApiMsgException(ApiEnum.API_REQUIRED_PARAM_VALUE_RANGE_ERROR.format(k));
                    }
                }
            }
        });

        ApiUserRequest apiUserRequest = reqApiParameterVO.getApiUserRequest();
        ApiParameterBO apiPreRequiredParamBO = new ApiParameterBO();
        apiPreRequiredParamBO.setApiKeyPO(apiKeyPO);
        apiPreRequiredParamBO.setApiBizMatchBO(apiBizMatchBO);
        apiPreRequiredParamBO.setReqApiParameterVO(reqApiParameterVO);
        apiPreRequiredParamBO.setUserRegisterBO(mappingRegisterBO);
        apiPreRequiredParamBO.setListUserFormBO(listMappingFormBO);
        apiPreRequiredParamBO.setHasLocalExist(false);

        //  撞库校验业务
        if (ApiBizTypeEnum.DATA_EXCHANGE.hasEnum(apiBizTypeEnum)) {
            String phoneMask = apiUserRequest.getPhoneMask();
            //  验证关键参数
            Assert.isNotEmptyThrows(phoneMask, new ApiMsgException(ApiEnum.API_REQUIRED_BASE_PARAM_NULL.format("phoneMask")));

            String city = mappingRegisterBO.getCity();
            Assert.isNotEmptyThrows(city, new ApiMsgException(ApiEnum.API_REQUIRED_BASE_PARAM_NULL.format("city")));
            Assert.isTrueThrows(city.length() >= 2, new ApiMsgException(ApiEnum.API_PARAM_ERROR));
            Assert.isTrueThrows(RegexUtils.isChinese(city), new ApiMsgException(ApiEnum.API_PARAM_CITY_ERROR));
        }

        //  进件业务时则验证-手机号是否已注册
        if (ApiBizTypeEnum.APPLY.hasEnum(apiBizTypeEnum)) {
            //  获取当前用户信息
            ChannelUserQO channelUserQO = ChannelUserQO.createPhone(mappingRegisterBO.getPhone());
            ChannelUserRegisterPO channelUserRegisterPO = channelUserService.get(channelUserQO);
            boolean hasLocalExist = ValidParam.isNotNull(channelUserRegisterPO);

            //  如果进件注册过将姓名更改
            if (hasLocalExist) {
                Long userId = channelUserRegisterPO.getId();
                //  如果是联登进来并且用户不填写表单，无姓名问题
                boolean hasFederateNotUserName = ValidParam.isEmpty(channelUserRegisterPO.getUserName());

                //  修改姓名，城市，性别，城市
                ChannelUserRegisterPO updateUser = new ChannelUserRegisterPO();
                updateUser.setId(userId);

                updateUser.setUserName(mappingRegisterBO.getUserName());
                if (ValidParam.isNotEmpty(mappingRegisterBO.getSex())) {
                    updateUser.setSex(mappingRegisterBO.getSex());
                }

                DistrictPO districtPO = DistrictCache.getByName(mapReqForm.get("city"));
                updateUser.setAreaName(districtPO.getName());
                updateUser.setAreaCode(districtPO.getCode());
                updateUser.setIsChannelRegister(ChannelIsRegisterEnum.OLD.getType());
                doubleWriteUserService.updateUser(updateUser);

                //  修改原有表单
                List<ChannelUserFormPO> listChannelUserFormPO = CopyUtils.copyList(listMappingFormBO, ChannelUserFormPO.class);
                IteratorUtils.array(listChannelUserFormPO, t -> {
                    t.setChannelId(loanChannelId);
                    t.setUserId(userId);
                });
                doubleWriteUserService.batchInsertUserForm(listChannelUserFormPO);

                //  如果是联登进来用户注册，无填写表单，并且后续API渠道触发改用户时则不判定用户已存在，将用户信息修改继续API渠道分发
                if (hasFederateNotUserName) {
                    apiPreRequiredParamBO.setHasFederateUser(true);
                    return apiPreRequiredParamBO;
                }
                //  特殊计划将直接返回
                boolean hasOnlySpecialPlan = apiBizMatchBO.hasOnlySpecialPlan();
                if (hasOnlySpecialPlan) {
                    //  判断是否能够正常分发crm
                    return apiPreRequiredParamBO;
                }
            }
        }
        return apiPreRequiredParamBO;
    }

    @Override
    public boolean hasLimitTime(ProductApplyFlowPO insertProductApplyFlowPO, ProductPlanPO productPlanPO, ProductApplyFlowStatusEnum productApplyFlowStatusEnum) {
        //  判断是否超出计划时间
        if (OpenTimeUtils.hasOpen(productPlanPO)) {
            return true;
        }
        //  插入日志数据
        insertProductApplyFlowPO.setStatus(productApplyFlowStatusEnum.getType());
        insertProductApplyFlowPO.setExceptionMsg("业务-超出计划时间");
        productApplyFlowService.insert(insertProductApplyFlowPO, true);
        return false;
    }

    @Override
    public boolean hasLimitTotal(ProductApplyFlowPO insertProductApplyFlowPO, ProductPlanPO productPlanPO, ProductApplyFlowStatusEnum productApplyFlowStatusEnum) {
        boolean hasPlanLimitTotalExceed = productPlanLimitService.hasPlanLimitTotalExceed(productPlanPO);
        if (hasPlanLimitTotalExceed) {
            insertProductApplyFlowPO.setStatus(productApplyFlowStatusEnum.getType());
            insertProductApplyFlowPO.setExceptionMsg("业务-机构计划超出");
            return true;
        }
        return false;
    }

    @Override
    public boolean hasChannelFilter(ProductApplyFlowPO insertProductApplyFlowPO, ProductPlanPO productPlanPO, Long loanChannelId, ProductApplyFlowStatusEnum productApplyFlowStatusEnum) {
        //  主体主键id
        Long loanProductId = productPlanPO.getLoanProductId();
        //  计划主键id
        Long loanProductPlanId = productPlanPO.getId();

        //  是否获取拥有屏蔽项
        ProductPlanFilterChannelPO productPlanFilterChannelPO = productPlanFilterChannelService.get(loanProductId, loanProductPlanId, loanChannelId);
        if (ValidParam.isNull(productPlanFilterChannelPO)) {
            return false;
        }

        insertProductApplyFlowPO.setStatus(productApplyFlowStatusEnum.getType());
        insertProductApplyFlowPO.setExceptionMsg("业务-此计划已对该渠道屏蔽");
        return true;
    }

    @Override
    public boolean hasExistMd5Filter(ProductApplyFlowPO insertProductApplyFlowPO, ProductPlanPO productPlanPO, String phoneMd5, ProductApplyFlowStatusEnum productApplyFlowStatusEnum) {
        //  是否为首次添加过滤md5标识
        Boolean md5ExistFilter = Md5DataFilterRedisKey.MD5_EXIST_FILTER.get(phoneMd5, Boolean.class);

        //  MD5库排重
        if (SwitchEnum.hasEnable(productPlanPO.getEnableFilterMd5())) {
            //  非首次添加md5时增加判断
            if (md5ExistFilter == null || !md5ExistFilter) {
                int row = apiDataFilterService.countByPhoneMd5(phoneMd5);
                if (row > 0) {
                    insertProductApplyFlowPO.setStatus(productApplyFlowStatusEnum.getType());
                    insertProductApplyFlowPO.setExceptionMsg("业务-[md5筛选库]中已存在该手机号md5");
                    productApplyFlowService.insert(insertProductApplyFlowPO, true);
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public boolean requiredApiChannelPlanVersion(ApiKeyPO apiKeyPO, ProductPlanPO productPlanPO) {
        Integer apiVersion = apiKeyPO.getApiVersion();
        Integer planVersion = productPlanPO.getVersionType();

        //  必须为平台计划则开启验证
        if (!productPlanTypeService.hasPlatformPlan(productPlanPO)) {
            return true;
        }
        //  如果为忽略模式则直接跳过
        if (ProductPlanVersionEnum.IGNORE.hasVersion(planVersion)) {
            return true;
        }
        //  上游广点通模式
        if (ApiVersionEnum.GDT_V4.hasVersion(apiVersion) && ProductPlanVersionEnum.ALL.hasVersion(planVersion)) {
            return true;
        }
        //  上游全流程模式
        if (ApiVersionEnum.ALL_V3.hasVersion(apiVersion) && ProductPlanVersionEnum.ALL.hasVersion(planVersion)) {
            return true;
        }
        //  上游半流程撞库进件模式-下游支持半流程撞库进件模式及全流程
        if (ApiVersionEnum.AUTH_V2.hasVersion(apiVersion)) {
            if (ProductPlanVersionEnum.ALL.hasVersion(planVersion) || ProductPlanVersionEnum.AUTH.hasVersion(planVersion)) {
                return true;
            }
        }
        //  上游半流程授权回调通知进件模式-下游支持半流程所有模式及全流程模式
        if (ApiVersionEnum.AUTH_NOTICE_CALL_V2.hasVersion(apiVersion)) {
            return ProductPlanVersionEnum.ALL.hasVersion(planVersion) || ProductPlanVersionEnum.AUTH.hasVersion(planVersion) || ProductPlanVersionEnum.AUTH_NOTICE_CALL.hasVersion(planVersion);
        }
        return false;
    }

    @Override
    public boolean requiredApiChannelPlanModeVersion(ApiKeyPO apiKeyPO, ProductPlanPO productPlanPO) {
        Integer apiVersionMode = apiKeyPO.getApiVersionMode();
        Integer planVersionMode = productPlanPO.getVersionMode();

        //  渠道md5对下游md5
        if (ApiVersionModeEnum.MD5.hasVersionMode(apiVersionMode) && ProductPlanVersionMode.MD5.hasVersionMode(planVersionMode)) {
            return true;
        }
        //  渠道8位对下游8位
        if (ApiVersionModeEnum.PHONE_MASK_8.hasVersionMode(apiVersionMode) && ProductPlanVersionMode.PHONE_MASK_8.hasVersionMode(planVersionMode)) {
            return true;
        }
        return false;
    }

    @Override
    public ProductApplyFlowPO requiredSucDataExchangeFlow(ApiRequiredFlowBO apiRequiredFlowBO) {
        ProductApplyFlowQO productApplyFlowQO = new ProductApplyFlowQO();
        productApplyFlowQO.setApiClientId(apiRequiredFlowBO.getApiClientId());
        productApplyFlowQO.setLoanChannelId(apiRequiredFlowBO.getLoanChannelId());
        productApplyFlowQO.setReqId(apiRequiredFlowBO.getReqId());
        productApplyFlowQO.setProductPlanId(apiRequiredFlowBO.getProductPlanId());
        productApplyFlowQO.setPhoneMd5(apiRequiredFlowBO.getPhoneMd5());
        productApplyFlowQO.setStatus(ProductApplyFlowStatusEnum.DATA_EXCHANGE_SUC.getType());

        //  查询是否渠道存在该流程
        List<ProductApplyFlowPO> list = productApplyFlowService.list(productApplyFlowQO);
        if (ValidParam.isEmpty(list)) {
            return null;
        }

        //  最新一条的机构计划
        list.sort(Comparator.comparing(ProductApplyFlowPO::getCreateTime, DATE_TIME_COMPARATOR.reversed()));
        return IteratorUtils.getFirst(list);
    }

    @Override
    public boolean requiredPlanField(List<ProductPlanFieldPO> listProductPlanFieldPO, Map<String, String> userForm) {
        //  该计划的区分类型
        Map<Integer, List<ProductPlanFieldPO>> mapProductPlanFormByType = CollUtils.groupByToLinked(listProductPlanFieldPO, t -> t.getType());
        //  是否资质全匹配标识
        boolean allMatch = true;

        //  全资质匹配
        List<ProductPlanFieldPO> listAllMatchMode = mapProductPlanFormByType.get(0);
        Map<String, List<ProductPlanFieldPO>> mapAllMatchModeByMappingName = CollUtils.groupByToLinked(listAllMatchMode, t -> t.getMappingName());
        //  根据映射值分组获取表单值
        Iterator<Map.Entry<String, List<ProductPlanFieldPO>>> allMatchModeIterator = IteratorUtils.entrySet(mapAllMatchModeByMappingName);
        while (allMatchModeIterator.hasNext()) {
            Map.Entry<String, List<ProductPlanFieldPO>> allMatchModeEntry = allMatchModeIterator.next();
            //  计划资质项名称(key)
            String fieldName = allMatchModeEntry.getKey();
            //  计划资质项值(value)
            List<ProductPlanFieldPO> fieldValue = allMatchModeEntry.getValue();
            //  获取用户资质进件值
            String applyValue = userForm.get(fieldName);
            String finalApplyValue = applyValue;

            //  匹配计划
            ProductPlanFieldPO match = CollUtils.findOne(fieldValue, t -> Eq.str(t.getMappingValue(), finalApplyValue));
            if (ValidParam.isNull(match)) {
                ProductPlanFieldPO productPlanFieldPO = IteratorUtils.getFirst(fieldValue);
                Log.get().warn("计划id:{}, 出现计划不匹配，字段值:{}, 匹配值:{}, 传递值:{}",
                    productPlanFieldPO.getProductPlanId(),
                    productPlanFieldPO.getMappingName(),
                    productPlanFieldPO.getMappingValue(),
                    applyValue
                );
                allMatch = false;
                break;
            }
        }

        //  多选其一匹配
        if (allMatch) {
            List<ProductPlanFieldPO> listAnyMode = mapProductPlanFormByType.get(1);
            // 如果多选其一匹配-集合为空则直接跳出此次循环
            if (ValidParam.isEmpty(listAnyMode)) {
                return true;
            }

            //  选中标识
            boolean chooseOne = false;
            //  根据映射值分组获取表单值
            Iterator<Map.Entry<String, List<ProductPlanFieldPO>>> anyModeIterator = IteratorUtils.entrySet(CollUtils.groupByToLinked(listAnyMode, t -> t.getMappingName()));
            while (anyModeIterator.hasNext()) {
                Map.Entry<String, List<ProductPlanFieldPO>> anyModeEntry = anyModeIterator.next();
                //  获取进件值
                String applyValue = userForm.get(anyModeEntry.getKey());
                List<String> listMappingValue = CollUtils.toList(anyModeEntry.getValue(), t -> t.getMappingValue());
                if (listMappingValue.contains(applyValue)) {
                    chooseOne = true;
                    break;
                }
            }
            //  如果两者模式都匹配成功则添加计划
            return chooseOne;
        }
        return false;
    }

    @Override
    public boolean requiredPlanPrice(ProductPlanPO productPlanPO, BigDecimal channelPrice) {
        //  计划单价
        BigDecimal price = productPlanPO.getPrice();
        //  判断渠道是否单价模式
        if (BigDecimalUtils.compare(channelPrice, 0) > 0) {
            //  计划价格 < 渠道价, 跳过
            return BigDecimalUtils.compare(price, channelPrice) != -1;
        }
        return true;
    }

    @Override
    public boolean requiredPlanPrice(BigDecimal finalPrice, BigDecimal channelPrice) {
        //  判断渠道是否单价模式
        if (BigDecimalUtils.compare(channelPrice, 0) > 0) {
            //  输入价格 < 渠道价, 跳过
            return BigDecimalUtils.compare(finalPrice, channelPrice) != -1;
        }
        return true;
    }

    @Override
    public boolean requiredProductAmount(ProductApplyFlowPO insertProductApplyFlowPO, ProductPlanPO productPlanPO, ProductApplyFlowStatusEnum productApplyFlowStatusEnum) {
        //  平台及平台分润不检查余额
        boolean hasPlatform = productPlanTypeService.hasPlatformPlan(productPlanPO);
        boolean hasPlatShare = productPlanTypeService.hasPlatShare(productPlanPO);
        if (hasPlatform || hasPlatShare) {
            return true;
        }

        //  检查机构余额
        if (productAmountService.isDeduct(productPlanPO.getProductBalance(), productPlanPO.getPrice())) {
            return true;
        }

        insertProductApplyFlowPO.setStatus(productApplyFlowStatusEnum.getType());
        insertProductApplyFlowPO.setExceptionMsg("业务-机构余额不足");
        productApplyFlowService.insert(insertProductApplyFlowPO, true);
        return false;
    }

    @Override
    public boolean requiredApplyForm(ProductApplyFlowPO insertProductApplyFlowPO, ProductPlanPO productPlanPO, Map<String, String> userFormMap) {
        //  获取计划资质
        List<ProductPlanFieldPO> listProductPlanForm = productPlanFieldService.listProductPlanField(ProductPlanFieldQO.create(CollUtils.newArrayList(productPlanPO)));
        if (ValidParam.isEmpty(listProductPlanForm)) {
            return true;
        }

        //  验证计划字段
        boolean required = this.requiredPlanField(listProductPlanForm, userFormMap);
        if (required) {
            return true;
        }

        insertProductApplyFlowPO.setStatus(ProductApplyFlowStatusEnum.APPLY_BIZ_ERROR.getType());
        insertProductApplyFlowPO.setExceptionMsg("进件资质不符合当前机构计划");
        productApplyFlowService.insert(insertProductApplyFlowPO, true);
        return false;
    }

    @Override
    public boolean requiredApplyCity(ProductApplyFlowPO insertProductApplyFlowPO, ApiUserRequest apiUserRequest, String sourceCityName) {
        boolean errorFlag = false;
        String city = apiUserRequest.getCity();

        //  验证是否与进件流程城市一致
        if (!Eq.str(sourceCityName, city)) {
            try {
                //  判断最后一位字符串都一样的情况下
                char[] applyFlowCityArray = sourceCityName.toCharArray();
                for (int i = 0; i < applyFlowCityArray.length - 1; i++) {
                    char c = applyFlowCityArray[i];
                    if (c != city.charAt(i)) {
                        errorFlag = true;
                        break;
                    }
                }
                //  如果一直到前一位都一样，默认为缺市这个字，将ApiUser的城市替换为流程发起时的城市名称
                apiUserRequest.setCity(sourceCityName);
            } catch (Exception e) {
                errorFlag = true;
            }

            if (errorFlag) {
                String msg = StringUtils.format("申请失败,当前进件发送[{}]城市与前置业务[{}]城市不符", city, sourceCityName);
                insertProductApplyFlowPO.setStatus(ProductApplyFlowStatusEnum.APPLY_BIZ_ERROR.getType());
                insertProductApplyFlowPO.setExceptionMsg(msg);
                productApplyFlowService.insert(insertProductApplyFlowPO, true);
            }
        }
        return !errorFlag;
    }

    @Override
    public RespPlatformPhoneMd5DataExchange requiredPlatformDataExchange(ProductApplyFlowPO insertProductApplyFlowPO, ApiHttpMessage apiHttpMessage,
                                                                         boolean hasPlatShare,
                                                                         ProductPlanPO productPlanPO) {
        RespPlatformPhoneMd5DataExchange apiPlatFormDataExchange = JsonUtils.toBean(apiHttpMessage.getResponseBody(), RespPlatformPhoneMd5DataExchange.class);
        String errorMsg = null;

        //  返回单价
        BigDecimal price = apiPlatFormDataExchange.getPrice();

        //  如果为空则设置我方平台中的logo体现
        if (ValidParam.isEmpty(apiPlatFormDataExchange.getLogoPath())) {
            apiPlatFormDataExchange.setLogoPath(productPlanPO.getLogoPath());
        }

        if (ValidParam.isEmpty(apiPlatFormDataExchange.getDisplayName())) {
            errorMsg = "业务失败, 返回【公司名称】为空";
        }
        if (ValidParam.isEmpty(apiPlatFormDataExchange.getProductName())) {
            errorMsg = "业务失败, 返回【产品名称】为空";
        }
        //  分润模式必传价格， 单价模式忽略
        if (hasPlatShare) {
            if (ValidParam.isNull(price)) {
                errorMsg = "业务失败, 返回【价格】为空";
            } else if (BigDecimalUtils.compare(price, 0) <= 0) {
                errorMsg = "业务失败, 返回【价格】非法";
            }
        }

        if (ValidParam.isNotEmpty(errorMsg)) {
            apiPlatFormDataExchange.setHasBizSuc(false);
            insertProductApplyFlowPO.setStatus(ProductApplyFlowStatusEnum.DATA_EXCHANGE_FAIL.getType());
            insertProductApplyFlowPO.setExceptionMsg(errorMsg);
            productApplyFlowService.insert(insertProductApplyFlowPO, true);
        }
        return apiPlatFormDataExchange;
    }

    @Override
    public RespPlatformMultiPhoneMaskDataExchange requiredPlatformPhoneMaskDataExchange(ProductApplyFlowPO insertProductApplyFlowPO, ApiHttpMessage apiHttpMessage,
                                                                                   boolean hasPlatShare,
                                                                                   ProductPlanPO productPlanPO) {

        RespPlatformMultiPhoneMaskDataExchange respData = JsonUtils.toBean(apiHttpMessage.getResponseBody(), RespPlatformMultiPhoneMaskDataExchange.class);
        if (respData == null) {
            insertProductApplyFlowPO.setStatus(ProductApplyFlowStatusEnum.DATA_EXCHANGE_FAIL.getType());
            insertProductApplyFlowPO.setExceptionMsg("掩码模式业务失败, 返回对象为空");
            productApplyFlowService.insert(insertProductApplyFlowPO, true);
            return new RespPlatformMultiPhoneMaskDataExchange();
        }

        List<RespPlatformPhoneMaskDataExchange> listPhoneMask = respData.getListPhoneMask();
        //  过滤为null的对象
        CollUtils.filter(listPhoneMask, t -> t == null);

        //  空对象返回
        if (ValidParam.isEmpty(listPhoneMask)) {
            respData.setHasBizSuc(false);
            insertProductApplyFlowPO.setStatus(ProductApplyFlowStatusEnum.DATA_EXCHANGE_FAIL.getType());
            insertProductApplyFlowPO.setExceptionMsg("业务失败, 无返回对象");
            productApplyFlowService.insert(insertProductApplyFlowPO, true);
            return new RespPlatformMultiPhoneMaskDataExchange();
        }

        String errorMsg = null;
        for (int i = 0; i < listPhoneMask.size(); i++) {
            RespPlatformPhoneMaskDataExchange respItem = listPhoneMask.get(i);
            if (ValidParam.isEmpty(respItem.getDisplayName())) {
                errorMsg = "业务失败, 返回【投放名称】为空";
                break;
            }
            if (ValidParam.isEmpty(respItem.getProductName())) {
                errorMsg = "业务失败, 返回【产品名称】为空";
                break;
            }

            //  返回单价
            BigDecimal price = respItem.getPrice();
            //  分润模式必传价格， 单价模式忽略
            if (hasPlatShare) {
                if (ValidParam.isNull(price)) {
                    errorMsg = "业务失败, 返回【价格】为空";
                    break;
                } else if (BigDecimalUtils.compare(price, 0) <= 0) {
                    errorMsg = "业务失败, 返回【价格】非法";
                    break;
                }
            }

            if (ValidParam.isEmpty(respItem.getLogoPath())) {
                respItem.setLogoPath(productPlanPO.getLogoPath());
            }
        }

        if (ValidParam.isNotEmpty(errorMsg)) {
            insertProductApplyFlowPO.setStatus(ProductApplyFlowStatusEnum.DATA_EXCHANGE_FAIL.getType());
            insertProductApplyFlowPO.setExceptionMsg(errorMsg);
            productApplyFlowService.insert(insertProductApplyFlowPO, true);
        }
        return respData;
    }

    @Override
    public RespPlatformFederateForm requiredPlatFormFederateDataExchange(ProductApplyFlowPO insertProductApplyFlowPO, ApiHttpMessage apiHttpMessage) {
        RespPlatformFederateForm respPlatformFederateForm = JsonUtils.toBean(apiHttpMessage.getResponseBody(), RespPlatformFederateForm.class);
        String errorMsg = null;

        if (ValidParam.isEmpty(respPlatformFederateForm.getCallUrl())) {
            errorMsg = "业务失败, 返回【回调地址】为空";
        }

        if (ValidParam.isNotEmpty(errorMsg)) {
            respPlatformFederateForm.setHasBizSuc(false);
            insertProductApplyFlowPO.setStatus(ProductApplyFlowStatusEnum.DATA_EXCHANGE_FAIL.getType());
            insertProductApplyFlowPO.setExceptionMsg(errorMsg);
            productApplyFlowService.insert(insertProductApplyFlowPO, true);
        }
        return respPlatformFederateForm;
    }

    @Override
    public RespOrgPhoneMaskDataExchange respOrgDataExchange(ProductApplyFlowPO insertProductApplyFlowPO, ApiHttpMessage apiHttpMessage, boolean hasPlatShare, ProductPlanPO productPlanPO) {
        RespOrgPhoneMaskDataExchange respOrgPhoneMaskDataExchange = JsonUtils.toBean(apiHttpMessage.getResponseBody(), RespOrgPhoneMaskDataExchange.class);
        return respOrgPhoneMaskDataExchange;
    }

    @Override
    public boolean requiredPhoneStatus(ProductApplyFlowPO insertProductApplyFlowPO, ProductPlanPO productPlanPO, String phone) {
        String apiClientId = insertProductApplyFlowPO.getApiClientId();
        //  计划空号检测状态
        boolean hasPlanDisable = SwitchEnum.hasDisable(productPlanPO.getEnableApplyEmptyCheck());
        //  获取用户信息
        ChannelUserRegisterPO userRegisterPO = channelUserService.get(ChannelUserQO.createPhone(phone));

        //  自有渠道-根据计划是否开关决定开启空号检测
        if (ValidParam.isEmpty(apiClientId)) {
            if (hasPlanDisable) {
                return true;
            }
            //  如果检测状态非空则不检测-后期要改为当前用户手机号月份大于3二次校验
            if (ValidParam.isNotNull(userRegisterPO) && ValidParam.isNotNull(userRegisterPO.getPhoneStatus())) {
                return true;
            }

            //  手机号码检测
            CheckPhoneStatusBO checkPhoneStatusBO = userPhoneAuthService.checkPhoneStatus(phone);

            //  更新用户空号检测标识状态
            ChannelUserRegisterPO updateUserPO = new ChannelUserRegisterPO();
            updateUserPO.setPhoneStatus(Integer.valueOf(checkPhoneStatusBO.getPhoneStatus()));
            updateUserPO.setOperatorType(Integer.valueOf(checkPhoneStatusBO.getCarrier()));
            updateUserPO.setId(userRegisterPO.getId());
            doubleWriteUserService.updateUser(updateUserPO);

            //  如果验证错误记录日志
            boolean hasPhoneError = checkPhoneStatusBO.hasErrorStats();
            if (hasPhoneError) {
                insertProductApplyFlowPO.setStatus(ProductApplyFlowStatusEnum.APPLY_BIZ_ERROR.getType());
                insertProductApplyFlowPO.setExceptionMsg(StringUtils.format("非法手机状态:[{}]", checkPhoneStatusBO.getPhoneStatusText()));
                productApplyFlowService.insert(insertProductApplyFlowPO, true);
                return false;
            }
            return true;
        }

        //  API渠道
        ApiKeyCache apiKeyCache = apiKeyCacheService.get(apiClientId);
        boolean hasApiKeyDisable = SwitchEnum.hasDisable(apiKeyCache.getEnableApplyEmptyCheck());
        //  如果API渠道关闭，根据计划是否开关决定开启空号检测
        if (hasApiKeyDisable) {
            if (hasPlanDisable) {
                return true;
            }
            //  后期要改为当前用户手机号月份大于3二次校验
            if (ValidParam.isNotNull(userRegisterPO) && ValidParam.isNotNull(userRegisterPO.getPhoneStatus())) {
                return true;
            }

            //  手机号码检测
            CheckPhoneStatusBO checkPhoneStatusBO = userPhoneAuthService.checkPhoneStatus(phone);

            //  更新用户空号检测标识状态
            ChannelUserRegisterPO updateUserPO = new ChannelUserRegisterPO();
            updateUserPO.setPhoneStatus(Integer.valueOf(checkPhoneStatusBO.getPhoneStatus()));
            updateUserPO.setOperatorType(Integer.valueOf(checkPhoneStatusBO.getCarrier()));
            updateUserPO.setId(userRegisterPO.getId());
            doubleWriteUserService.updateUser(updateUserPO);

            //  如果验证错误记录日志
            boolean hasPhoneError = checkPhoneStatusBO.hasErrorStats();
            if (hasPhoneError) {
                insertProductApplyFlowPO.setStatus(ProductApplyFlowStatusEnum.APPLY_BIZ_ERROR.getType());
                insertProductApplyFlowPO.setExceptionMsg(StringUtils.format("非法手机状态:[{}]", checkPhoneStatusBO.getPhoneStatusText()));
                productApplyFlowService.insert(insertProductApplyFlowPO, true);
                return false;
            }
        }

        //  如果API渠道端打开，全计划开启空号检测
        //  手机号码检测
        CheckPhoneStatusBO checkPhoneStatusBO = userPhoneAuthService.checkPhoneStatus(phone);
        //  更新用户空号检测标识状态
        ChannelUserRegisterPO updateUserPO = new ChannelUserRegisterPO();
        updateUserPO.setPhoneStatus(Integer.valueOf(checkPhoneStatusBO.getPhoneStatus()));
        updateUserPO.setOperatorType(Integer.valueOf(checkPhoneStatusBO.getCarrier()));
        updateUserPO.setId(userRegisterPO.getId());
        doubleWriteUserService.updateUser(updateUserPO);

        //  如果验证错误记录日志
        boolean hasPhoneError = checkPhoneStatusBO.hasErrorStats();
        if (hasPhoneError) {
            insertProductApplyFlowPO.setStatus(ProductApplyFlowStatusEnum.APPLY_BIZ_ERROR.getType());
            insertProductApplyFlowPO.setExceptionMsg(StringUtils.format("非法手机状态:[{}]", checkPhoneStatusBO.getPhoneStatusText()));
            productApplyFlowService.insert(insertProductApplyFlowPO, true);
            return false;
        }
        return true;
    }

    @Override
    public boolean hasHttpTimeOut(ProductApplyFlowPO insertProductApplyFlowPO, ApiHttpMessage apiHttpMessage, ProductApplyFlowStatusEnum productApplyFlowStatusEnum) {
        if (!apiHttpMessage.hasReqTimeout()) {
            return false;
        }

        //  超时记录日志
        insertProductApplyFlowPO.setExceptionMsg("[机构/平台]端超时");
        insertProductApplyFlowPO.setStatus(productApplyFlowStatusEnum.getType());
        productApplyFlowService.insert(insertProductApplyFlowPO, true);
        return true;
    }

    @Override
    public boolean hasHttpExp(ProductApplyFlowPO insertProductApplyFlowPO, ApiHttpMessage apiHttpMessage, boolean enableInsert, ProductApplyFlowStatusEnum productApplyFlowStatusEnum) {
        if (ValidParam.isNull(apiHttpMessage.getErrorMsg())) {
            return false;
        }

        //  开启插入则记录流程状态
        if (enableInsert) {
            //  如果出现异常情况记录日志
            insertProductApplyFlowPO.setExceptionMsg(apiHttpMessage.getErrorMsg());
            insertProductApplyFlowPO.setStackMsg(apiHttpMessage.getStackMsg());
            insertProductApplyFlowPO.setStatus(productApplyFlowStatusEnum.getType());
            productApplyFlowService.insert(insertProductApplyFlowPO, true);
        }
        return true;
    }

    @Override
    public boolean hasHttpRespBizSuc(ProductApplyFlowPO insertProductApplyFlowPO, ApiHttpMessage apiHttpMessage, boolean enableInsert, ProductApplyFlowStatusEnum productApplyFlowStatusEnum) {
        //  验证返回失败
        if (apiHttpMessage.hasSuc()) {
            return true;
        }

        //  开启插入则记录流程状态
        if (enableInsert) {
            insertProductApplyFlowPO.setStatus(productApplyFlowStatusEnum.getType());
            insertProductApplyFlowPO.setExceptionMsg("处理响应结果-对方返回结果[失败]");
            productApplyFlowService.insert(insertProductApplyFlowPO, true);
        }
        return false;
    }

    @Override
    public boolean hasNoticeHttpRespSuc(ProductApplyFlowPO insertProductApplyFlowPO, ApiHttpMessage apiHttpMessage, ProductApplyFlowStatusEnum productApplyFlowStatusEnum) {
        //  是否业务状态成功
        if (apiHttpMessage.hasSuc()) {
            return true;
        }
        //  是否HTTP错误
        if (ValidParam.isNull(apiHttpMessage.getErrorMsg())) {
            return true;
        }
        insertProductApplyFlowPO.setStatus(productApplyFlowStatusEnum.getType());
        insertProductApplyFlowPO.setStackMsg(apiHttpMessage.getStackMsg());
        insertProductApplyFlowPO.setExceptionMsg("处理[进件回调]判断响应结果为[失败]");
        productApplyFlowService.insert(insertProductApplyFlowPO, true);
        return false;
    }

    @Override
    public boolean existHistoryUser(ApiCheckHistoryUserBO apiCheckHistoryUserBO) {
        Integer asc = 0;
        Integer historyUserProportion;
        Integer historyUserOrderType;

        //  获取渠道/API渠道设定参数
        if (ValidParam.isNotNull(apiCheckHistoryUserBO.getApiKeyPO())) {
            ApiKeyPO apiKeyPO = apiCheckHistoryUserBO.getApiKeyPO();
            historyUserProportion = apiKeyPO.getApiHistoryUserProportion();
            historyUserOrderType = apiKeyPO.getApiHistoryUserOrderType();
        } else {
            ChannelPO channelPO = apiCheckHistoryUserBO.getChannelPO();
            historyUserProportion = channelPO.getHistoryUserProportion();
            historyUserOrderType = channelPO.getHistoryUserOrderType();
        }

        //  如果填写0的话默认最小值是1(避免全部归0无法匹配问题，也避免下面的禁用状态检查0会自动返回false)
        if (historyUserProportion == 0) {
            historyUserProportion = 1;
        }

        //  检测是否禁用状态
        if (SwitchEnum.hasDisable(historyUserProportion)) {
            return false;
        }

        //  检测历史库是否存在
        String phoneMd5 = apiCheckHistoryUserBO.getPhoneMd5();
        ChannelUserRegisterPO historyUserPO = channelHistoryUserService.get(ChannelUserQO.createPhoneMd5(phoneMd5));
        if (ValidParam.isNull(historyUserPO)) {
            return false;
        }

        Long maxId = channelHistoryUserService.getMaxId();
        Long historyUserId = historyUserPO.getId();

        //  正序
        if (Eq.object(historyUserOrderType, asc)) {
            BigDecimal division = BigDecimalUtils.division(historyUserId, maxId, RoundingMode.HALF_UP);
            Integer ascPercent = BigDecimalUtils.multiply(division, 100).intValue();
            return ascPercent <= historyUserProportion;
        }

        //  倒序
        //  避免全部归100无法匹配问题
        if (historyUserProportion == 100) {
            historyUserProportion =  historyUserProportion -1;
        }
        BigDecimal division = BigDecimalUtils.division(BigDecimalUtils.minus(maxId, historyUserId), maxId, RoundingMode.HALF_UP);
        Integer descPercent = BigDecimalUtils.multiply(division, 100).intValue();
        return descPercent >= historyUserProportion;
    }

    @Override
    public List<ChannelUserRegisterPO> existHistoryUserPhoneMask(ApiCheckHistoryUserBO apiCheckHistoryUserBO) {
        String phoneMask = apiCheckHistoryUserBO.getPhoneMask();
        Integer asc = 0;
        Integer historyUserProportion;
        Integer historyUserOrderType;

        //  获取渠道/API渠道设定参数
        if (ValidParam.isNotNull(apiCheckHistoryUserBO.getApiKeyPO())) {
            ApiKeyPO apiKeyPO = apiCheckHistoryUserBO.getApiKeyPO();
            historyUserProportion = apiKeyPO.getApiHistoryUserProportion();
            historyUserOrderType = apiKeyPO.getApiHistoryUserOrderType();
        } else {
            ChannelPO channelPO = apiCheckHistoryUserBO.getChannelPO();
            historyUserProportion = channelPO.getHistoryUserProportion();
            historyUserOrderType = channelPO.getHistoryUserOrderType();
        }

        //  如果填写0的话默认最小值是1(避免全部归0无法匹配问题，也避免下面的禁用状态检查0会自动返回false)
        if (historyUserProportion == 0) {
            historyUserProportion = 1;
        }

        //  如果不开启比例则直接返回空
        if (SwitchEnum.hasDisable(historyUserProportion)) {
            return Empty.list();
        }

        //  获取最大id
        Long maxId = channelHistoryUserService.getMaxId();
        //  获取小数比例
        BigDecimal ratio = BigDecimalUtils.division(historyUserProportion, 100);
        Long endRange = BigDecimalUtils.multiply(ratio, maxId).longValue();

        //  计算范围
        Long rangeStartId;
        Long rangeEndId;
        if (Eq.object(historyUserOrderType, asc)) {
            //  正序
            rangeStartId = 1L;
            rangeEndId = endRange;
        } else {
            //  倒序
            rangeStartId = (maxId - endRange) + 1;
            rangeEndId = maxId;
        }

        //  获取老库掩码值
        ChannelUserQO channelUserQO = ChannelUserQO.createPhoneMaskRange(phoneMask, rangeStartId, rangeEndId);
        List<ChannelUserRegisterPO> listRightMatchPhone = channelHistoryUserService.listRightMatchPhone(channelUserQO);
        return listRightMatchPhone;
    }
}
